package org.devocean.groupbuying.service.payment.paypal;

import java.util.Calendar;
import java.util.Map;

import org.devocean.groupbuying.domain.Cart;
import org.devocean.groupbuying.domain.CartItem;
import org.devocean.groupbuying.domain.Deal;
import org.devocean.groupbuying.domain.PaypalPayment;
import org.devocean.groupbuying.service.CartService;
import org.devocean.groupbuying.service.DealService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.paypal.sdk.core.nvp.NVPAPICaller;
import com.paypal.sdk.core.nvp.NVPDecoder;
import com.paypal.sdk.core.nvp.NVPEncoder;
import com.paypal.sdk.exceptions.PayPalException;
import com.paypal.sdk.profiles.APIProfile;

@Service
public class PayPalServiceImpl extends Throwable implements PayPalService {

	@Autowired
	private APIProfile profile;

	@Value("#{PaypalProfiles['returnURL']}")
	private String returnURL;

	@Value("#{PaypalProfiles['cancelURL']}")
	private String cancelURL;

	@Value("#{PaypalProfiles['redirectURL']}")
	private String redirectURL;

	public String setExpressCheckout(Cart cart, String action) throws Exception {

		// Fill NVP Request
		NVPEncoder encoder = new NVPEncoder();
		encoder.add("METHOD", "SetExpressCheckout");
		encoder.add("PAYMENTREQUEST_0_AMT", cart.getAmount().toString());
		encoder.add("PAYMENTREQUEST_0_ITEMAMT", cart.getAmount().toString());
		encoder.add("RETURNURL", returnURL + "/" + action);
		encoder.add("CANCELURL", cancelURL);
		encoder.add("PAYMENTREQUEST_0_PAYMENTACTION", action);
		encoder.add("PAYMENTREQUEST_0_CURRENCYCODE", "USD");
		encoder.add("SOLUTIONTYPE", "Sole");
		encoder.add("LANDINGPAGE", "Login");
		encoder.add("BRANDNAME", "CloudsWave");
		encoder.add("HDRIMG",
				"http://www.cloudswave.com/wp-content/themes/premium-theme/img/logo.png");

		// Fill NVP PayPal Cart items
		for (int i = 0; i < cart.getCartItems().size(); i++) {

			CartItem item = cart.getCartItems().get(i);
			encoder.add("L_PAYMENTREQUEST_0_NAME" + i, item.getDiscountInfo());
			encoder.add("L_PAYMENTREQUEST_0_AMT" + i, item.getUnitPrice()
					.toString());
			encoder.add("L_PAYMENTREQUEST_0_QTY" + i, item.getQuantity()
					.toString());

		}

		// Request Sender
		NVPAPICaller caller = new NVPAPICaller();
		// Response Reciever
		NVPDecoder decoder = new NVPDecoder();
		final String result;

		try {
			caller.setupConnection(profile);
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause());
		}

		try {
			decoder.decode(caller.call(encoder.encode()));
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		final Map<Object, Object> response = decoder.getMap();

		if (response.get("ACK").equals("Success")) {
			result = redirectURL + response.get("TOKEN");
		} else {
			throw new Exception(response.get("L_LONGMESSAGE0").toString()
					+ "Caused by : " + "PayPal", this);
		}

		return result;
	}

	public Map doExpressCheckoutPayment(Cart cart, String payerID,
			String token, String action) throws Exception {

		NVPEncoder encoder = new NVPEncoder();
		encoder.add("METHOD", "DoExpressCheckoutPayment");
		encoder.add("PAYMENTREQUEST_0_AMT", cart.getAmount().toString());
		encoder.add("PAYMENTREQUEST_0_ITEMAMT", cart.getAmount().toString());
		encoder.add("PAYMENTREQUEST_0_PAYMENTACTION", action);
		encoder.add("TOKEN", token);
		encoder.add("PAYERID", payerID);

		for (int i = 0; i < cart.getCartItems().size(); i++) {

			CartItem item = cart.getCartItems().get(i);
			encoder.add("L_PAYMENTREQUEST_0_NAME" + i, item.getDiscountInfo());
			encoder.add("L_PAYMENTREQUEST_0_AMT" + i, item.getUnitPrice()
					.toString());
			encoder.add("L_PAYMENTREQUEST_0_QTY" + i, item.getQuantity()
					.toString());

		}

		NVPAPICaller caller = new NVPAPICaller();
		try {
			caller.setupConnection(profile);
		} catch (PayPalException e) {
			System.err.println(e.getMessage());
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		NVPDecoder decoder = new NVPDecoder();
		try {
			decoder.decode(caller.call(encoder.encode()));
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause());
		}

		final Map<Object, Object> response = decoder.getMap();

		if (response.get("ACK").equals("Success")) {
			System.out.println("successful payment");
			return response;
		} else {
			System.err.println(response.get("L_LONGMESSAGE0").toString());
			throw new Exception(response.get("L_LONGMESSAGE0").toString()
					+ "Caused by : " + "paypal", this);
		}

	}

	public void doCapture(final PaypalPayment paypalPayment) throws Exception {

		NVPEncoder encoder = new NVPEncoder();
		encoder.add("METHOD", "DoCapture");
		encoder.add("AMT", Double.toString(paypalPayment.getAmount()));
		encoder.add("AUTHORIZATIONID", paypalPayment.getTransactionID());
		encoder.add("COMPLETETYPE", "NotComplete");

		NVPAPICaller caller = new NVPAPICaller();
		try {
			caller.setupConnection(profile);
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		NVPDecoder decoder = new NVPDecoder();
		try {
			decoder.decode(caller.call(encoder.encode()));
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		final Map<Object, Object> response = decoder.getMap();

		if (response.get("ACK").equals("Success")) {
			paypalPayment.setTransactionID(decoder.get("TRANSACTIONID"));
			paypalPayment.getPayment().setStatus(decoder.get("PAYMENTSTATUS"));
			paypalPayment.getPayment().setStatusDate(
					Calendar.getInstance().getTime());
		} else {
			throw new Exception(response.get("L_LONGMESSAGE0").toString()
					+ "Caused by : " + "paypal", this);
		}

		// TODO delegate update paypalPayment

	}

	public boolean doVerify(PaypalPayment paypalPayment) throws Exception {

		boolean flag = false;

		NVPEncoder encoder = new NVPEncoder();
		encoder.add("METHOD", "GetTransactionDetails");
		encoder.add("AUTHORIZATIONID", paypalPayment.getTransactionID());

		NVPAPICaller caller = new NVPAPICaller();
		try {
			caller.setupConnection(profile);
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		NVPDecoder decoder = new NVPDecoder();
		try {
			decoder.decode(caller.call(encoder.encode()));
		} catch (PayPalException e) {
			e.printStackTrace();
			throw new Exception(e.getMessage() + "Caused by : " + e.getCause(),
					e.getCause());
		}
		final Map<Object, Object> response = decoder.getMap();

		if (response.get("ACK").equals("Success")) {
			paypalPayment.setTransactionID(decoder.get("TRANSACTIONID"));
			if (!paypalPayment.getPayment().getStatus()
					.equalsIgnoreCase(decoder.get("PAYMENTSTATUS"))) {
				paypalPayment.getPayment().setStatus(
						decoder.get("PAYMENTSTATUS"));
				paypalPayment.getPayment().setStatusDate(
						Calendar.getInstance().getTime());
				flag = true;
			}

		} else {
			throw new Exception(response.get("L_LONGMESSAGE0").toString()
					+ "Caused by : " + "paypal", this);
		}

		// TODO delegate update paypalPayment
		return flag;

	}
}
